/* This test concentrates on fragmented TLS handshake message across multiple TLS records 
(e.g. when a certificate message is splitted into multiple fragments). 
The Cipher Suite used was TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (0xc024). */

#include   "nx_api.h"
#include   "nx_secure_tls_api.h"
//#include   "test_ca_cert.c"
#include   "nx_secure_tls.h"
#include   "tls_test_utility.h"

extern VOID    test_control_return(UINT status);


#if !defined(NX_SECURE_TLS_CLIENT_DISABLED) && defined(NX_SECURE_ENABLE_ECC_CIPHERSUITE) && !defined(NX_SECURE_DISABLE_X509)
#define NUM_PACKETS                 24
#define PACKET_SIZE                 1536
#define PACKET_POOL_SIZE            (NUM_PACKETS * (PACKET_SIZE + sizeof(NX_PACKET)))
#define THREAD_STACK_SIZE           1024
#define ARP_CACHE_SIZE              1024
#define METADATA_SIZE               16000
#define SERVER_PORT                 4433

#define TLS_OFFSET                  66
#define TLS_PACKET_BUFFER_SZ        60000

/* Define the ThreadX and NetX object control blocks...  */

static TX_THREAD                thread_0;
static TX_THREAD                thread_1;
static NX_PACKET_POOL           pool_0;
static NX_IP                    ip_0;
static UINT                     error_counter;

static NX_TCP_SOCKET            client_socket_0;
static NX_TCP_SOCKET            server_socket_0;
static NX_SECURE_TLS_SESSION    tls_client_session_0;
static NX_SECURE_X509_CERT      client_trusted_ca;
extern const NX_SECURE_TLS_CRYPTO
                                nx_crypto_tls_ciphers;

extern const NX_SECURE_TLS_CRYPTO nx_crypto_tls_ciphers_ecc;
extern const USHORT nx_crypto_ecc_supported_groups[];
extern const NX_CRYPTO_METHOD *nx_crypto_ecc_curves[];
extern const UINT nx_crypto_ecc_supported_groups_size;

static ULONG                    pool_0_memory[PACKET_POOL_SIZE / sizeof(ULONG)];
static ULONG                    thread_0_stack[THREAD_STACK_SIZE / sizeof(ULONG)];
static ULONG                    thread_1_stack[THREAD_STACK_SIZE / sizeof(ULONG)];
static ULONG                    ip_0_stack[THREAD_STACK_SIZE / sizeof(ULONG)];
static ULONG                    arp_cache[ARP_CACHE_SIZE];
static UCHAR                    client_metadata[METADATA_SIZE];

static UCHAR                    tls_packet_buffer[TLS_PACKET_BUFFER_SZ];
static UCHAR                    remote_server_certs_buffer[(sizeof(NX_SECURE_X509_CERT) + 2000) * 3];

static UCHAR clientkeyexchange[128];

/* frame1 consists of server_hello, and certificate(fragment). */
static UCHAR frame1[] = {
  0x00, 0x15, 0x5d, 0x64, 0x1a, 0x03, 0x00, 0x15, 0x5d, 0xb9, 0x20, 0x17,
  0x08, 0x00, 0x45, 0x00, 0x05, 0xdc, 0xa1, 0x6b, 0x40, 0x00, 0x24, 0x06,
  0x46, 0xa8, 0x34, 0xaa, 0x38, 0x0f, 0xac, 0x12, 0x50, 0x3d, 0x22, 0xb3,
  0x9b, 0xdc, 0x40, 0xbf, 0xe2, 0x7b, 0xef, 0x86, 0xe1, 0x63, 0x80, 0x10,
  0x00, 0xeb, 0xf5, 0x7d, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0xd5, 0xe7,
  0x2e, 0xc6, 0xa1, 0x5c, 0xf4, 0x30, 0x16, 0x03, 0x03, 0x00, 0x4a, 0x02,
  0x00, 0x00, 0x46, 0x03, 0x03, 0x3f, 0x00, 0x16, 0x61, 0xed, 0x87, 0x8f,
  0x90, 0xea, 0x57, 0x54, 0x04, 0x4c, 0xe3, 0xa4, 0xb2, 0xbc, 0x68, 0xd9,
  0x21, 0x41, 0xfd, 0x34, 0x16, 0x12, 0xa0, 0x13, 0x1f, 0xc9, 0x4e, 0xe8,
  0x65, 0x00, 0xc0, 0x24, 0x00, 0x00, 0x1e, 0xff, 0x01, 0x00, 0x01, 0x00,
  0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01,
  0x02, 0x00, 0x23, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00,
  0x00, 0x16, 0x03, 0x03, 0x02, 0x00, 0x0b, 0x00, 0x08, 0xd6, 0x00, 0x08,
  0xd3, 0x00, 0x05, 0x1d, 0x30, 0x82, 0x05, 0x19, 0x30, 0x82, 0x04, 0x9e,
  0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x03, 0xe0, 0xc4, 0xcd, 0xd3,
  0xf9, 0xca, 0xf4, 0x25, 0xd8, 0x17, 0xcc, 0x5b, 0xfd, 0xa1, 0x2f, 0x30,
  0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03, 0x30,
  0x4c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
  0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
  0x0c, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e,
  0x63, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1d,
  0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x45, 0x43, 0x43,
  0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65, 0x72, 0x76,
  0x65, 0x72, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x39, 0x31,
  0x30, 0x32, 0x39, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d,
  0x32, 0x30, 0x31, 0x30, 0x32, 0x39, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30,
  0x5a, 0x30, 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
  0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
  0x08, 0x13, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f,
  0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07,
  0x52, 0x65, 0x64, 0x6d, 0x6f, 0x6e, 0x64, 0x31, 0x1e, 0x30, 0x1c, 0x06,
  0x03, 0x55, 0x04, 0x0a, 0x13, 0x15, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73,
  0x6f, 0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74,
  0x69, 0x6f, 0x6e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03,
  0x0c, 0x1f, 0x2a, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x2e,
  0x61, 0x7a, 0x75, 0x72, 0x65, 0x2d, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
  0x73, 0x2d, 0x69, 0x6e, 0x74, 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x59, 0x30,
  0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08,
  0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04,
  0x47, 0xe5, 0x23, 0x74, 0xb3, 0x30, 0xcf, 0xa8, 0xc4, 0x1d, 0x31, 0x5e,
  0x2c, 0xd4, 0x25, 0xf7, 0x4a, 0x4a, 0xee, 0xd4, 0xf8, 0xcf, 0x68, 0xb4,
  0x42, 0xc1, 0x52, 0x80, 0x1f, 0x0f, 0x6f, 0x95, 0x0e, 0x85, 0x72, 0x3a,
  0x24, 0x8c, 0x88, 0x91, 0xd5, 0x66, 0x7a, 0x36, 0x16, 0x22, 0x1b, 0x88,
  0x93, 0xce, 0x6d, 0xce, 0x78, 0xe6, 0xb5, 0x56, 0xea, 0x04, 0x28, 0xf7,
  0x1a, 0x1a, 0x64, 0x5d, 0xa3, 0x82, 0x03, 0x2e, 0x30, 0x82, 0x03, 0x2a,
  0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80,
  0x14, 0xa3, 0x9d, 0xe6, 0x1f, 0xf9, 0xda, 0x39, 0x4f, 0xc0, 0x6e, 0xe8,
  0x91, 0xcb, 0x95, 0xa5, 0xda, 0x31, 0xe2, 0x0a, 0x9f, 0x30, 0x1d, 0x06,
  0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb7, 0xf5, 0xb3, 0x86,
  0x69, 0x78, 0x4a, 0x30, 0x48, 0x93, 0xad, 0x0b, 0xf2, 0xa6, 0x14, 0x66,
  0xe0, 0xd3, 0x2f, 0xc7, 0x30, 0x6d, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04,
  0x66, 0x30, 0x64, 0x82, 0x1f, 0x2a, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61,
  0x74, 0x65, 0x2e, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x2d, 0x64, 0x65, 0x76,
  0x69, 0x63, 0x65, 0x73, 0x2d, 0x69, 0x6e, 0x74, 0x2e, 0x6e, 0x65, 0x74,
  0x82, 0x22, 0x2a, 0x2e, 0x76, 0x32, 0x2e, 0x70, 0x72, 0x69, 0x76, 0x61,
  0x74, 0x65, 0x16, 0x03, 0x03, 0x02, 0x00, 0x2e, 0x61, 0x7a, 0x75, 0x72,
  0x65, 0x2d, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2d, 0x69, 0x6e,
  0x74, 0x2e, 0x6e, 0x65, 0x74, 0x82, 0x1d, 0x70, 0x72, 0x69, 0x76, 0x61,
  0x74, 0x65, 0x2e, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x2d, 0x64, 0x65, 0x76,
  0x69, 0x63, 0x65, 0x73, 0x2d, 0x69, 0x6e, 0x74, 0x2e, 0x6e, 0x65, 0x74,
  0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04,
  0x03, 0x02, 0x07, 0x80, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04,
  0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03,
  0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30,
  0x69, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x62, 0x30, 0x60, 0x30, 0x2e,
  0xa0, 0x2c, 0xa0, 0x2a, 0x86, 0x28, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
  0x2f, 0x63, 0x72, 0x6c, 0x33, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65,
  0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x73, 0x63, 0x61, 0x2d,
  0x65, 0x63, 0x63, 0x2d, 0x67, 0x31, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x2e,
  0xa0, 0x2c, 0xa0, 0x2a, 0x86, 0x28, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
  0x2f, 0x63, 0x72, 0x6c, 0x34, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65,
  0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x73, 0x63, 0x61, 0x2d,
  0x65, 0x63, 0x63, 0x2d, 0x67, 0x31, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x4c,
  0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x45, 0x30, 0x43, 0x30, 0x37, 0x06,
  0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xfd, 0x6c, 0x01, 0x01, 0x30, 0x2a,
  0x30, 0x28, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01,
  0x16, 0x1c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77,
  0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63,
  0x6f, 0x6d, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x08, 0x06, 0x06, 0x67, 0x81,
  0x0c, 0x01, 0x02, 0x02, 0x30, 0x7b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
  0x05, 0x07, 0x01, 0x01, 0x04, 0x6f, 0x30, 0x6d, 0x30, 0x24, 0x06, 0x08,
  0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74,
  0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x64, 0x69,
  0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x45,
  0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x39,
  0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x61, 0x63, 0x65, 0x72,
  0x74, 0x73, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e,
  0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74,
  0x45, 0x43, 0x43, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x53, 0x65, 0x72,
  0x76, 0x65, 0x72, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x0c, 0x06,
  0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30,
  0x82, 0x01, 0x04, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79,
  0x02, 0x04, 0x02, 0x04, 0x81, 0xf5, 0x04, 0x81, 0xf2, 0x00, 0xf0, 0x00,
  0x77, 0x00, 0xbb, 0xd9, 0xdf, 0xbc, 0x1f, 0x8a, 0x71, 0xb5, 0x93, 0x94,
  0x23, 0x97, 0xaa, 0x92, 0x7b, 0x47, 0x38, 0x57, 0x95, 0x0a, 0xab, 0x52,
  0xe8, 0x1a, 0x90, 0x96, 0x64, 0x36, 0x8e, 0x1e, 0xd1, 0x85, 0x00, 0x00,
  0x01, 0x6e, 0x19, 0x7d, 0x2f, 0x72, 0x00, 0x00, 0x04, 0x03, 0x00, 0x48,
  0x30, 0x46, 0x02, 0x21, 0x00, 0xf7, 0x48, 0xc7, 0xbc, 0xab, 0xe2, 0x6e,
  0xab, 0xa3, 0x71, 0x16, 0x03, 0x03, 0x02, 0x00, 0x37, 0x89, 0xdd, 0x6c,
  0xac, 0x35, 0xda, 0x9e, 0xac, 0x41, 0x50, 0xea, 0xc7, 0x20, 0x2a, 0x89,
  0x37, 0xac, 0x9f, 0xcb, 0x8a, 0x64, 0x02, 0x21, 0x00, 0x86, 0xb2, 0xdd,
  0xa8, 0x3a, 0xe7, 0x48, 0x03, 0xc6, 0xc6, 0x93, 0x41, 0xc2, 0x61, 0x36,
  0xdb, 0x61, 0xb6, 0x87, 0x01, 0x33, 0x1c, 0x70, 0x3a, 0x9c, 0xd6, 0xac,
  0x1d, 0x5b, 0xd9, 0x58, 0xec, 0x00, 0x75, 0x00, 0x87, 0x75, 0xbf, 0xe7,
  0x59, 0x7c, 0xf8, 0x8c, 0x43, 0x99, 0x5f, 0xbd, 0xf3, 0x6e, 0xff, 0x56,
  0x8d, 0x47, 0x56, 0x36, 0xff, 0x4a, 0xb5, 0x60, 0xc1, 0xb4, 0xea, 0xff,
  0x5e, 0xa0, 0x83, 0x0f, 0x00, 0x00, 0x01, 0x6e, 0x19, 0x7d, 0x2f, 0xaa,
  0x00, 0x00, 0x04, 0x03, 0x00, 0x46, 0x30, 0x44, 0x02, 0x20, 0x63, 0x0d,
  0xd0, 0x3c, 0x09, 0x5b, 0xd9, 0x26, 0x31, 0xbd, 0xad, 0x79, 0x4e, 0xfe,
  0x61, 0x7f, 0xcc, 0x41, 0x26, 0x40, 0x0d, 0x7f, 0xc8, 0x37, 0xda, 0x6a,
  0xaa, 0x95, 0x8e, 0x39, 0x2e, 0x36, 0x02, 0x20, 0x56, 0x77, 0x64, 0xde,
  0xb3, 0x2e, 0x61, 0x08, 0x88, 0xe6, 0x8c, 0x88, 0x97, 0xd8, 0x6a, 0x90,
  0x89, 0xb3, 0xc9, 0x95, 0x42, 0x26, 0xb8, 0xd1, 0xda, 0x4b, 0x64, 0x40,
  0x76, 0x1e, 0x2b, 0xc9, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce,
  0x3d, 0x04, 0x03, 0x03, 0x03, 0x69, 0x00, 0x30, 0x66, 0x02, 0x31, 0x00,
  0xd4, 0x27, 0xe0, 0xc2, 0x93, 0x3a, 0x65, 0xd6, 0x26, 0x1e, 0xb1, 0x41,
  0x80, 0xa8, 0x41, 0x06, 0x5e, 0x7f, 0x3a, 0x60, 0x28, 0x26, 0x57, 0xd0,
  0x35, 0xd8, 0x8c, 0x72, 0x8c, 0x85, 0x78, 0x45, 0x73, 0xc7, 0xfa, 0x2a,
  0x1c, 0x33, 0x02, 0xff, 0xb3, 0xb8, 0xb4, 0x3c, 0xe2, 0x6a, 0xf4, 0x8b,
  0x02, 0x31, 0x00, 0xad, 0x0b, 0x86, 0x1b, 0xd8, 0x35, 0x84, 0x15, 0x3c,
  0xce, 0xd2, 0x11, 0xc0, 0xda, 0x0d, 0x97, 0x94, 0x80, 0x57, 0x44, 0x77,
  0x95, 0x0b, 0x9e, 0x1c, 0x30, 0xe7, 0x99, 0xee, 0x69, 0x59, 0x04, 0x9e,
  0x4b, 0x4a, 0x8e, 0x2f, 0xab, 0xe6, 0xa5, 0x2a, 0xa6, 0xcb, 0x57, 0xb5,
  0x7e, 0x78, 0xab, 0x00, 0x03, 0xb0, 0x30, 0x82, 0x03, 0xac, 0x30, 0x82,
  0x02, 0x94, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x0a, 0xcb, 0x28,
  0xba, 0x46, 0x5e, 0xe5, 0x39, 0x08, 0x76, 0x74, 0x70, 0xf3, 0xcd, 0xc6,
  0x12, 0x30
};
UINT frame1_len = 1514;

/* Frame 2 consists of certificate(continuation), server_key_exchange, 
   certificate_request, server_hello_done*/
static UCHAR frame2[] = {
  0x00, 0x15, 0x5d, 0x64, 0x1a, 0x03, 0x00, 0x15, 0x5d, 0xb9, 0x20, 0x17,
  0x08, 0x00, 0x45, 0x00, 0x04, 0xb0, 0xa1, 0x6c, 0x40, 0x00, 0x24, 0x06,
  0x47, 0xd3, 0x34, 0xaa, 0x38, 0x0f, 0xac, 0x12, 0x50, 0x3d, 0x22, 0xb3,
  0x9b, 0xdc, 0x40, 0xbf, 0xe8, 0x23, 0xef, 0x86, 0xe1, 0x63, 0x80, 0x18,
  0x00, 0xeb, 0x71, 0x20, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0xd5, 0xe7,
  0x2e, 0xc6, 0xa1, 0x5c, 0xf4, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
  0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00, 0x30, 0x61, 0x31, 0x0b,
  0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
  0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44, 0x69,
  0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x19,
  0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77, 0x77,
  0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f,
  0x6d, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x17,
  0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x47, 0x6c, 0x6f,
  0x62, 0x61, 0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30,
  0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x33, 0x30, 0x38, 0x31, 0x32, 0x30,
  0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x33, 0x30, 0x33, 0x30, 0x38,
  0x31, 0x32, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x4c, 0x31, 0x0b, 0x30,
  0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15,
  0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44, 0x69, 0x67,
  0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x16, 0x03, 0x03, 0x02,
  0x00, 0x63, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
  0x1d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x45, 0x43,
  0x43, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65, 0x72,
  0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07,
  0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04,
  0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0xe2, 0x08, 0x42, 0xea, 0x77, 0xd8,
  0x24, 0xde, 0xa0, 0x2c, 0x64, 0xa4, 0x13, 0xce, 0x40, 0x9c, 0x23, 0x72,
  0xa9, 0x02, 0x0a, 0x0e, 0x37, 0x3f, 0x21, 0x36, 0xb8, 0x8d, 0x53, 0x14,
  0xf6, 0xd5, 0x91, 0x95, 0x4b, 0xf3, 0x96, 0x02, 0x8d, 0x71, 0x1e, 0xc4,
  0xd8, 0xcb, 0xa7, 0x9f, 0x5e, 0xef, 0xa0, 0xe6, 0x7f, 0x5a, 0x92, 0x11,
  0x96, 0x53, 0x6f, 0xeb, 0xc0, 0xcb, 0x3f, 0xae, 0xfd, 0x5b, 0x3f, 0x47,
  0x24, 0xe7, 0x9a, 0x07, 0x2e, 0x96, 0xbe, 0xa8, 0x2f, 0xbb, 0x57, 0x18,
  0xaf, 0x71, 0xa4, 0xbd, 0x78, 0x3a, 0x1e, 0xe8, 0x5b, 0x3c, 0x6b, 0x64,
  0x11, 0x2b, 0xcc, 0x34, 0x2b, 0x8c, 0xa3, 0x82, 0x01, 0x21, 0x30, 0x82,
  0x01, 0x1d, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
  0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e,
  0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02,
  0x01, 0x86, 0x30, 0x34, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
  0x01, 0x01, 0x04, 0x28, 0x30, 0x26, 0x30, 0x24, 0x06, 0x08, 0x2b, 0x06,
  0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74, 0x70,
  0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x64, 0x69, 0x67, 0x69,
  0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x42, 0x06, 0x03,
  0x55, 0x1d, 0x1f, 0x04, 0x3b, 0x30, 0x39, 0x30, 0x37, 0xa0, 0x35, 0xa0,
  0x33, 0x86, 0x31, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72,
  0x6c, 0x33, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e,
  0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74,
  0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x41,
  0x2e, 0x63, 0x72, 0x6c, 0x30, 0x3d, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04,
  0x36, 0x30, 0x34, 0x30, 0x32, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00, 0x30,
  0x2a, 0x30, 0x28, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02,
  0x01, 0x16, 0x1c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77,
  0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e,
  0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x1d, 0x06, 0x03, 0x55,
  0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xa3, 0x9d, 0xe6, 0x1f, 0xf9, 0xda,
  0x39, 0x4f, 0xc0, 0x6e, 0xe8, 0x91, 0xcb, 0x95, 0xa5, 0xda, 0x31, 0xe2,
  0x0a, 0x9f, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30,
  0x16, 0x80, 0x14, 0x03, 0xde, 0x50, 0x35, 0x56, 0xd1, 0x4c, 0xbb, 0x66,
  0xf0, 0xa3, 0xe2, 0x1b, 0x1b, 0xc3, 0x97, 0xb2, 0x3d, 0xd1, 0x55, 0x30,
  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c,
  0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xc7, 0x8a, 0xa0, 0x43, 0x4b,
  0xec, 0x74, 0xc9, 0xc5, 0xab, 0xd5, 0x1f, 0x30, 0x35, 0x36, 0x6e, 0x98,
  0x56, 0x7b, 0x48, 0xac, 0x05, 0x63, 0xae, 0x7b, 0x9a, 0x57, 0x24, 0x57,
  0xcc, 0x6f, 0xfa, 0xde, 0xab, 0x6d, 0x9c, 0xc7, 0xb6, 0x16, 0x03, 0x03,
  0x00, 0xda, 0xba, 0xec, 0xce, 0xe7, 0xca, 0x73, 0x64, 0xdb, 0xdf, 0x04,
  0x37, 0x0a, 0x00, 0x49, 0xb3, 0x3f, 0x9f, 0x26, 0xad, 0x91, 0x8c, 0x20,
  0xe8, 0x1f, 0x88, 0x0e, 0x2a, 0xfb, 0x66, 0x37, 0xc8, 0x30, 0xe8, 0xd2,
  0xc2, 0x24, 0xa7, 0x45, 0x48, 0x2d, 0xea, 0x01, 0x50, 0x4a, 0x31, 0x94,
  0x13, 0xdf, 0x8d, 0x5f, 0xda, 0x2a, 0xbb, 0x49, 0x3c, 0x61, 0xf3, 0x79,
  0xc8, 0x9c, 0x66, 0x92, 0x1a, 0x96, 0x2a, 0xf4, 0x7b, 0x36, 0x58, 0xa3,
  0x2c, 0x41, 0x10, 0x74, 0x1a, 0xd3, 0xed, 0x48, 0xb6, 0xd2, 0xbb, 0x8a,
  0x06, 0x45, 0x71, 0x33, 0x10, 0x30, 0x7a, 0x7a, 0x98, 0x21, 0xdd, 0x24,
  0xb9, 0xec, 0x9c, 0xb5, 0x92, 0x07, 0xad, 0x83, 0xc6, 0xc4, 0x6a, 0xf8,
  0x77, 0xe6, 0x35, 0xbe, 0x13, 0x0f, 0x27, 0x64, 0xb2, 0x43, 0xbf, 0x83,
  0xe9, 0x77, 0x56, 0xdb, 0x08, 0x87, 0x94, 0x47, 0x14, 0xf5, 0x5f, 0x28,
  0xaf, 0xa3, 0x68, 0x4c, 0x83, 0x8f, 0x60, 0xf7, 0x96, 0x80, 0x79, 0x85,
  0x6a, 0x76, 0x26, 0x9d, 0x95, 0x0c, 0x20, 0x03, 0x8d, 0x3e, 0xee, 0x7a,
  0x28, 0x65, 0x64, 0x66, 0xa4, 0xd9, 0x83, 0xea, 0x99, 0x74, 0xcd, 0x6e,
  0x4d, 0x7d, 0x1c, 0xeb, 0x8d, 0xb2, 0xc5, 0xaf, 0x16, 0x1b, 0x4e, 0xc8,
  0xf3, 0x55, 0xea, 0x88, 0x38, 0x11, 0x34, 0x1d, 0x11, 0xaf, 0x3f, 0x07,
  0xa8, 0x4f, 0x6a, 0xd2, 0x74, 0x11, 0x2f, 0x2a, 0xfc, 0x73, 0xb7, 0x5f,
  0xc2, 0x15, 0x43, 0x05, 0x6c, 0xd6, 0x7d, 0xda, 0x02, 0xbd, 0x22, 0x9b,
  0x4f, 0xd3, 0xf9, 0x77, 0x16, 0x03, 0x03, 0x00, 0x95, 0x0c, 0x00, 0x00,
  0x91, 0x03, 0x00, 0x17, 0x41, 0x04, 0xe4, 0xeb, 0xa8, 0x86, 0x86, 0x52,
  0x0e, 0xb4, 0x82, 0xcd, 0xca, 0x4d, 0xfe, 0x35, 0xeb, 0xb5, 0xc8, 0x9e,
  0x1f, 0x66, 0xe1, 0x47, 0x5c, 0xeb, 0xd8, 0xa3, 0x53, 0xfb, 0x6a, 0x59,
  0x7c, 0x45, 0xf4, 0xa6, 0x6a, 0xee, 0x71, 0xd0, 0xeb, 0x2b, 0xd1, 0x62,
  0xc0, 0xaa, 0x78, 0xc6, 0x06, 0xe3, 0xa1, 0x4a, 0xff, 0x85, 0x4b, 0xab,
  0x31, 0xb4, 0x0c, 0xa7, 0x67, 0x8f, 0x12, 0x9e, 0xfc, 0x44, 0x04, 0x03,
  0x00, 0x48, 0x30, 0x46, 0x02, 0x21, 0x00, 0xb1, 0x12, 0xfc, 0x29, 0x74,
  0x2c, 0xb8, 0x6f, 0xd9, 0xbc, 0xf6, 0x57, 0x85, 0x27, 0xbf, 0x0c, 0x7e,
  0x04, 0xb2, 0x44, 0x61, 0x87, 0xb5, 0xbd, 0x86, 0xa1, 0xf8, 0xbb, 0xee,
  0xd5, 0xde, 0x6f, 0x02, 0x21, 0x00, 0xc3, 0xae, 0x2b, 0xe4, 0xb0, 0x71,
  0x31, 0xf6, 0xe9, 0x2b, 0x78, 0x9b, 0x00, 0x12, 0xe5, 0x85, 0x79, 0x2e,
  0x66, 0x96, 0xd2, 0x7a, 0x5c, 0xad, 0xf1, 0x3a, 0xea, 0x22, 0xe4, 0x26,
  0x8b, 0xb9, 0x16, 0x03, 0x03, 0x00, 0x3a, 0x0d, 0x00, 0x00, 0x36, 0x03,
  0x01, 0x02, 0x40, 0x00, 0x2e, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x08,
  0x07, 0x08, 0x08, 0x08, 0x09, 0x08, 0x0a, 0x08, 0x0b, 0x08, 0x04, 0x08,
  0x05, 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x03, 0x03, 0x02,
  0x03, 0x03, 0x01, 0x02, 0x01, 0x03, 0x02, 0x02, 0x02, 0x04, 0x02, 0x05,
  0x02, 0x06, 0x02, 0x00, 0x00, 0x16, 0x03, 0x03, 0x00, 0x04, 0x0e, 0x00,
  0x00, 0x00
};
unsigned int frame2_len = 1214;

static UCHAR ca_cert_der[] = {
  0x30, 0x82, 0x03, 0xac, 0x30, 0x82, 0x02, 0x94,
  0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x0a,
  0xcb, 0x28, 0xba, 0x46, 0x5e, 0xe5, 0x39, 0x08,
  0x76, 0x74, 0x70, 0xf3, 0xcd, 0xc6, 0x12, 0x30,
  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
  0x0d, 0x01, 0x01, 0x0c, 0x05, 0x00, 0x30, 0x61,
  0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
  0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x15, 0x30,
  0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c,
  0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74,
  0x20, 0x49, 0x6e, 0x63, 0x31, 0x19, 0x30, 0x17,
  0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77,
  0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63,
  0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31,
  0x20, 0x30, 0x1e, 0x06, 0x03, 0x55, 0x04, 0x03,
  0x13, 0x17, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65,
  0x72, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61,
  0x6c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43,
  0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30,
  0x33, 0x30, 0x38, 0x31, 0x32, 0x30, 0x30, 0x30,
  0x30, 0x5a, 0x17, 0x0d, 0x32, 0x33, 0x30, 0x33,
  0x30, 0x38, 0x31, 0x32, 0x30, 0x30, 0x30, 0x30,
  0x5a, 0x30, 0x4c, 0x31, 0x0b, 0x30, 0x09, 0x06,
  0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
  0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04,
  0x0a, 0x13, 0x0c, 0x44, 0x69, 0x67, 0x69, 0x43,
  0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31,
  0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x03,
  0x13, 0x1d, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65,
  0x72, 0x74, 0x20, 0x45, 0x43, 0x43, 0x20, 0x53,
  0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65,
  0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x30,
  0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48,
  0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81,
  0x04, 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0xe2,
  0x08, 0x42, 0xea, 0x77, 0xd8, 0x24, 0xde, 0xa0,
  0x2c, 0x64, 0xa4, 0x13, 0xce, 0x40, 0x9c, 0x23,
  0x72, 0xa9, 0x02, 0x0a, 0x0e, 0x37, 0x3f, 0x21,
  0x36, 0xb8, 0x8d, 0x53, 0x14, 0xf6, 0xd5, 0x91,
  0x95, 0x4b, 0xf3, 0x96, 0x02, 0x8d, 0x71, 0x1e,
  0xc4, 0xd8, 0xcb, 0xa7, 0x9f, 0x5e, 0xef, 0xa0,
  0xe6, 0x7f, 0x5a, 0x92, 0x11, 0x96, 0x53, 0x6f,
  0xeb, 0xc0, 0xcb, 0x3f, 0xae, 0xfd, 0x5b, 0x3f,
  0x47, 0x24, 0xe7, 0x9a, 0x07, 0x2e, 0x96, 0xbe,
  0xa8, 0x2f, 0xbb, 0x57, 0x18, 0xaf, 0x71, 0xa4,
  0xbd, 0x78, 0x3a, 0x1e, 0xe8, 0x5b, 0x3c, 0x6b,
  0x64, 0x11, 0x2b, 0xcc, 0x34, 0x2b, 0x8c, 0xa3,
  0x82, 0x01, 0x21, 0x30, 0x82, 0x01, 0x1d, 0x30,
  0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
  0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff,
  0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55,
  0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
  0x02, 0x01, 0x86, 0x30, 0x34, 0x06, 0x08, 0x2b,
  0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04,
  0x28, 0x30, 0x26, 0x30, 0x24, 0x06, 0x08, 0x2b,
  0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86,
  0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
  0x6f, 0x63, 0x73, 0x70, 0x2e, 0x64, 0x69, 0x67,
  0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f,
  0x6d, 0x30, 0x42, 0x06, 0x03, 0x55, 0x1d, 0x1f,
  0x04, 0x3b, 0x30, 0x39, 0x30, 0x37, 0xa0, 0x35,
  0xa0, 0x33, 0x86, 0x31, 0x68, 0x74, 0x74, 0x70,
  0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x33, 0x2e,
  0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74,
  0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x44, 0x69, 0x67,
  0x69, 0x43, 0x65, 0x72, 0x74, 0x47, 0x6c, 0x6f,
  0x62, 0x61, 0x6c, 0x52, 0x6f, 0x6f, 0x74, 0x43,
  0x41, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x3d, 0x06,
  0x03, 0x55, 0x1d, 0x20, 0x04, 0x36, 0x30, 0x34,
  0x30, 0x32, 0x06, 0x04, 0x55, 0x1d, 0x20, 0x00,
  0x30, 0x2a, 0x30, 0x28, 0x06, 0x08, 0x2b, 0x06,
  0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c,
  0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f,
  0x77, 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69,
  0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d,
  0x2f, 0x43, 0x50, 0x53, 0x30, 0x1d, 0x06, 0x03,
  0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xa3,
  0x9d, 0xe6, 0x1f, 0xf9, 0xda, 0x39, 0x4f, 0xc0,
  0x6e, 0xe8, 0x91, 0xcb, 0x95, 0xa5, 0xda, 0x31,
  0xe2, 0x0a, 0x9f, 0x30, 0x1f, 0x06, 0x03, 0x55,
  0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
  0x03, 0xde, 0x50, 0x35, 0x56, 0xd1, 0x4c, 0xbb,
  0x66, 0xf0, 0xa3, 0xe2, 0x1b, 0x1b, 0xc3, 0x97,
  0xb2, 0x3d, 0xd1, 0x55, 0x30, 0x0d, 0x06, 0x09,
  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
  0x0c, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
  0xc7, 0x8a, 0xa0, 0x43, 0x4b, 0xec, 0x74, 0xc9,
  0xc5, 0xab, 0xd5, 0x1f, 0x30, 0x35, 0x36, 0x6e,
  0x98, 0x56, 0x7b, 0x48, 0xac, 0x05, 0x63, 0xae,
  0x7b, 0x9a, 0x57, 0x24, 0x57, 0xcc, 0x6f, 0xfa,
  0xde, 0xab, 0x6d, 0x9c, 0xc7, 0xb6, 0xba, 0xec,
  0xce, 0xe7, 0xca, 0x73, 0x64, 0xdb, 0xdf, 0x04,
  0x37, 0x0a, 0x00, 0x49, 0xb3, 0x3f, 0x9f, 0x26,
  0xad, 0x91, 0x8c, 0x20, 0xe8, 0x1f, 0x88, 0x0e,
  0x2a, 0xfb, 0x66, 0x37, 0xc8, 0x30, 0xe8, 0xd2,
  0xc2, 0x24, 0xa7, 0x45, 0x48, 0x2d, 0xea, 0x01,
  0x50, 0x4a, 0x31, 0x94, 0x13, 0xdf, 0x8d, 0x5f,
  0xda, 0x2a, 0xbb, 0x49, 0x3c, 0x61, 0xf3, 0x79,
  0xc8, 0x9c, 0x66, 0x92, 0x1a, 0x96, 0x2a, 0xf4,
  0x7b, 0x36, 0x58, 0xa3, 0x2c, 0x41, 0x10, 0x74,
  0x1a, 0xd3, 0xed, 0x48, 0xb6, 0xd2, 0xbb, 0x8a,
  0x06, 0x45, 0x71, 0x33, 0x10, 0x30, 0x7a, 0x7a,
  0x98, 0x21, 0xdd, 0x24, 0xb9, 0xec, 0x9c, 0xb5,
  0x92, 0x07, 0xad, 0x83, 0xc6, 0xc4, 0x6a, 0xf8,
  0x77, 0xe6, 0x35, 0xbe, 0x13, 0x0f, 0x27, 0x64,
  0xb2, 0x43, 0xbf, 0x83, 0xe9, 0x77, 0x56, 0xdb,
  0x08, 0x87, 0x94, 0x47, 0x14, 0xf5, 0x5f, 0x28,
  0xaf, 0xa3, 0x68, 0x4c, 0x83, 0x8f, 0x60, 0xf7,
  0x96, 0x80, 0x79, 0x85, 0x6a, 0x76, 0x26, 0x9d,
  0x95, 0x0c, 0x20, 0x03, 0x8d, 0x3e, 0xee, 0x7a,
  0x28, 0x65, 0x64, 0x66, 0xa4, 0xd9, 0x83, 0xea,
  0x99, 0x74, 0xcd, 0x6e, 0x4d, 0x7d, 0x1c, 0xeb,
  0x8d, 0xb2, 0xc5, 0xaf, 0x16, 0x1b, 0x4e, 0xc8,
  0xf3, 0x55, 0xea, 0x88, 0x38, 0x11, 0x34, 0x1d,
  0x11, 0xaf, 0x3f, 0x07, 0xa8, 0x4f, 0x6a, 0xd2,
  0x74, 0x11, 0x2f, 0x2a, 0xfc, 0x73, 0xb7, 0x5f,
  0xc2, 0x15, 0x43, 0x05, 0x6c, 0xd6, 0x7d, 0xda,
  0x02, 0xbd, 0x22, 0x9b, 0x4f, 0xd3, 0xf9, 0x77
};
unsigned int ca_cert_der_len = 944;

static UCHAR  client_random_bytes[] = {
  0x61, 0xbb, 0xd3, 0x7f, 0x07, 0xee, 0x43, 0x95,
  0xbb, 0x9a, 0xa7, 0x5e, 0x90, 0x4c, 0x39, 0xe3,
  0x94, 0x8b, 0xab, 0x2b, 0xef, 0x3a, 0x04, 0x65,
  0x18, 0x61, 0xb5, 0xe3, 0x47, 0x01, 0x51, 0xff
};
unsigned int client_random_bytes_len = 32;

extern NX_CRYPTO_METHOD crypto_method_md5;
extern NX_CRYPTO_METHOD crypto_method_sha1;
extern NX_CRYPTO_METHOD crypto_method_tls_prf_1;
extern NX_CRYPTO_METHOD crypto_method_sha256;
extern NX_CRYPTO_METHOD crypto_method_tls_prf_sha256;
extern NX_CRYPTO_METHOD crypto_method_ecdhe;
extern NX_CRYPTO_METHOD crypto_method_ecdsa;
extern NX_CRYPTO_METHOD crypto_method_aes_cbc_128;
extern NX_CRYPTO_METHOD crypto_method_hmac_sha384;
extern NX_CRYPTO_METHOD crypto_method_tls_prf_sha384;
extern NX_CRYPTO_METHOD crypto_method_sha384;
extern NX_CRYPTO_METHOD crypto_method_hkdf;
extern NX_CRYPTO_METHOD crypto_method_hmac;

NX_SECURE_TLS_CIPHERSUITE_INFO _ntest_crypto_ciphersuite_lookup_table_ecc_sha384[] =
{
    /* Ciphersuite,                           public cipher,            public_auth,              session cipher & cipher mode,   iv size, key size,  hash method,                    hash size, TLS PRF */
    {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, &crypto_method_ecdhe,     &crypto_method_ecdsa,     &crypto_method_aes_cbc_128,     16,      16,        &crypto_method_hmac_sha384,     32,        &crypto_method_tls_prf_sha384},

};

NX_SECURE_X509_CRYPTO _ntest_crypto_x509_cipher_lookup_table_ecc_sha384[] =
{
    /* OID identifier,                        public cipher,            hash method */
    {NX_SECURE_TLS_X509_TYPE_ECDSA_SHA_384,  &crypto_method_ecdsa,     &crypto_method_sha384},
    {NX_SECURE_TLS_X509_TYPE_ECDSA_SHA_256,  &crypto_method_ecdsa,     &crypto_method_sha256},

};

const NX_SECURE_TLS_CRYPTO ntest_crypto_tls_ciphers_ecc =
{
    /* Ciphersuite lookup table and size. */
    _ntest_crypto_ciphersuite_lookup_table_ecc_sha384,
    sizeof(_ntest_crypto_ciphersuite_lookup_table_ecc_sha384) / sizeof(NX_SECURE_TLS_CIPHERSUITE_INFO),

#ifndef NX_SECURE_DISABLE_X509
    /* X.509 certificate cipher table and size. */
    _ntest_crypto_x509_cipher_lookup_table_ecc_sha384,
    sizeof(_ntest_crypto_x509_cipher_lookup_table_ecc_sha384) / sizeof(NX_SECURE_X509_CRYPTO),
#endif

    /* TLS version-specific methods. */
#if (NX_SECURE_TLS_TLS_1_0_ENABLED || NX_SECURE_TLS_TLS_1_1_ENABLED)
    &crypto_method_md5,
    &crypto_method_sha1,
    &crypto_method_tls_prf_1,
#endif

#if (NX_SECURE_TLS_TLS_1_2_ENABLED)
    &crypto_method_sha256,
    &crypto_method_tls_prf_sha256,
#endif

#if (NX_SECURE_TLS_TLS_1_3_ENABLED)
    &crypto_method_hkdf,
    &crypto_method_hmac,
    &crypto_method_ecdhe,
#endif
};

/* Define thread prototypes.  */
static VOID    ntest_0_entry(ULONG thread_input);
static VOID    ntest_1_entry(ULONG thread_input);
extern VOID    _nx_ram_network_driver_1500(struct NX_IP_DRIVER_STRUCT *driver_req);


/* Define what the initial system looks like.  */


static VOID _error_print(char *file, unsigned int line)
{
    printf("Error at %s:%d\n", file, line);
    error_counter++;
}
#define ERROR_COUNTER() _error_print(__FILE__, __LINE__);

#ifdef CTEST
void test_application_define(void *first_unused_memory);
void test_application_define(void *first_unused_memory)
#else
VOID    nx_secure_tls_handshake_fragmentation_ecc_test_application_define(void *first_unused_memory)
#endif
{
UINT     status;
CHAR    *pointer;


    error_counter = 0;


    /* Setup the working pointer.  */
    pointer =  (CHAR *) first_unused_memory;

    /* Create the server thread.  */
    tx_thread_create(&thread_0, "thread 0", ntest_0_entry, 0,
                     thread_0_stack, sizeof(thread_0_stack),
                     7, 7, TX_NO_TIME_SLICE, TX_AUTO_START);

    /* Create the client thread.  */
    tx_thread_create(&thread_1, "thread 1", ntest_1_entry, 0,
                     thread_1_stack, sizeof(thread_1_stack),
                     8, 8, TX_NO_TIME_SLICE, TX_AUTO_START);

    /* Initialize the NetX system.  */
    nx_system_initialize();

    /* Create a packet pool.  */
    status =  nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", PACKET_SIZE,
                                    pool_0_memory, PACKET_POOL_SIZE);
    if (status)
    {
        ERROR_COUNTER();
    }

    /* Create an IP instance.  */
    status = nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(1, 2, 3, 4), 0xFFFFFF00UL,
                          &pool_0, _nx_ram_network_driver_1500,
                          ip_0_stack, sizeof(ip_0_stack), 1);
    if (status)
    {
        ERROR_COUNTER();
    }

    /* Enable ARP and supply ARP cache memory for IP Instance 0.  */
    status =  nx_arp_enable(&ip_0, (VOID *)arp_cache, sizeof(arp_cache));
    if (status)
    {
        ERROR_COUNTER();
    }

    /* Enable TCP traffic.  */
    status =  nx_tcp_enable(&ip_0);
    if (status)
    {
        ERROR_COUNTER();
    }

    nx_secure_tls_initialize();
}

static VOID client_tls_setup(NX_SECURE_TLS_SESSION *tls_session_ptr)
{
UINT status;

    status = nx_secure_tls_session_create(tls_session_ptr,
                                          &ntest_crypto_tls_ciphers_ecc,
                                          client_metadata,
                                          sizeof(client_metadata));
    if (status)
    {
        ERROR_COUNTER();
    }

    /* Initialize ECC parameters for this session. */                                               
    status = nx_secure_tls_ecc_initialize(tls_session_ptr,
                                              nx_crypto_ecc_supported_groups,
                                              nx_crypto_ecc_supported_groups_size,
                                              nx_crypto_ecc_curves);
    /* Check status.  */
    if (status)
    {
        ERROR_COUNTER();
    }

    status = nx_secure_x509_certificate_initialize(&client_trusted_ca,
                                                   ca_cert_der,
                                                   ca_cert_der_len, NX_NULL, 0, NULL, 0, NX_SECURE_X509_KEY_TYPE_NONE);
    if (status)
    {
        ERROR_COUNTER();
    }

    status = nx_secure_tls_trusted_certificate_add(tls_session_ptr,
                                                   &client_trusted_ca);
    if (status)
    {
        ERROR_COUNTER();
    }

}


static void ntest_0_entry(ULONG thread_input)
{
UINT i;
UINT status;
ULONG response_length;
NX_PACKET *send_packet_1;
NX_PACKET *send_packet_2;
NX_PACKET *send_packet_3;
NX_PACKET *receive_packet;
ULONG      bytes_copied;

    /* Print out test information banner.  */
    printf("NetX Secure Test:   TLS Multiple Handshake Messages Test using ECC...............");

    /* Create TCP socket. */
    status = nx_tcp_socket_create(&ip_0, &server_socket_0, "Server socket", NX_IP_NORMAL,
                                  NX_DONT_FRAGMENT, NX_IP_TIME_TO_LIVE, 8192, NX_NULL, NX_NULL);
    if (status)
    {
        ERROR_COUNTER();
    }

    status = nx_tcp_server_socket_listen(&ip_0, SERVER_PORT, &server_socket_0, 5, NX_NULL);
    if (status)
    {
        ERROR_COUNTER();
    }

    for (i = 0; i < 1; i++)
    {

        /* Make sure client thread is ready. */
        tx_thread_suspend(&thread_0);


        status = nx_tcp_server_socket_accept(&server_socket_0, NX_WAIT_FOREVER);
        if (status)
        {
            ERROR_COUNTER();
        }

        /* Receive ClientHello. */
        status = nx_tcp_socket_receive(&server_socket_0, &receive_packet, NX_WAIT_FOREVER);
        EXPECT_EQ(NX_SUCCESS, status);

        /* Release the ClientHello packet. */
        nx_packet_release(receive_packet);

		    /* send packet_1: server_hello, and certificate(fragment)  */
        status = nx_packet_allocate(&pool_0, &send_packet_1, NX_IPv4_TCP_PACKET, NX_WAIT_FOREVER);
        EXPECT_EQ(NX_SUCCESS, status);

		    status = nx_packet_data_append(send_packet_1, frame1 + TLS_OFFSET, frame1_len - TLS_OFFSET, &pool_0, NX_WAIT_FOREVER);
		    EXPECT_EQ(NX_SUCCESS, status);

        status = nx_tcp_socket_send(&server_socket_0, send_packet_1, NX_WAIT_FOREVER);
        EXPECT_EQ(NX_SUCCESS, status);

		    /* send packet_2: certificate(continuation), server_key_exchange, certificate_request, server_hello_done  */
		    status = nx_packet_allocate(&pool_0, &send_packet_2, NX_IPv4_TCP_PACKET, NX_WAIT_FOREVER);
		    EXPECT_EQ(NX_SUCCESS, status);

		    status = nx_packet_data_append(send_packet_2, frame2 + TLS_OFFSET, frame2_len - TLS_OFFSET, &pool_0, NX_WAIT_FOREVER);
		    EXPECT_EQ(NX_SUCCESS, status);

        status = nx_tcp_socket_send(&server_socket_0, send_packet_2, NX_WAIT_FOREVER);
        EXPECT_EQ(NX_SUCCESS, status);


        /* Receive Certificate*/
        status = nx_tcp_socket_receive(&server_socket_0, &receive_packet, NX_WAIT_FOREVER);
        EXPECT_EQ(NX_SUCCESS, status);

        /* Receive ClientKeyExchange*/
        status = nx_tcp_socket_receive(&server_socket_0, &receive_packet, NX_WAIT_FOREVER);
        EXPECT_EQ(NX_SUCCESS, status);

        /* Receive ChangeCipher */
        status = nx_tcp_socket_receive(&server_socket_0, &receive_packet, NX_WAIT_FOREVER);
        EXPECT_EQ(NX_SUCCESS, status);

        /* Receive TLS Finish */
        status = nx_tcp_socket_receive(&server_socket_0, &receive_packet, NX_WAIT_FOREVER);
        EXPECT_EQ(NX_SUCCESS, status);

        nx_tcp_socket_disconnect(&server_socket_0, NX_NO_WAIT);
        nx_tcp_server_socket_unaccept(&server_socket_0);
        nx_tcp_server_socket_relisten(&ip_0, SERVER_PORT, &server_socket_0);
    }

    tx_thread_sleep(10);

    if (error_counter)
    {
        printf("ERROR!\n");
        test_control_return(1);
    }
    else
    {
        printf("SUCCESS!\n");
        test_control_return(0);
    }
}

/* This is almost the copy of _nx_secure_tls_session_start(), execpt that we manually set clientHello_andom into tls_session,
    which is used to calculate the hash and verify public key by nx_secure_process_server_key_exchange().*/
UINT ntest_nx_secure_tls_session_start(NX_SECURE_TLS_SESSION *tls_session, NX_TCP_SOCKET *tcp_socket,
                                  UINT wait_option)
{
UINT       status = NX_NOT_SUCCESSFUL;
UINT       error_return;
#ifndef NX_SECURE_TLS_CLIENT_DISABLED
NX_PACKET *send_packet;
#endif

    /* Get the protection. */
    tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER);

    /* Assign the packet pool from which TLS will allocate internal message packets. */
    tls_session -> nx_secure_tls_packet_pool = tcp_socket -> nx_tcp_socket_ip_ptr -> nx_ip_default_packet_pool;

    /* Assign the TCP socket to the TLS session. */
    tls_session -> nx_secure_tls_tcp_socket = tcp_socket;

    /* Reset the record queue. */
    tls_session -> nx_secure_record_queue_header = NX_NULL;
    tls_session -> nx_secure_record_decrypted_packet = NX_NULL;

    /* Make sure we are starting with a fresh session. */
    tls_session -> nx_secure_tls_local_session_active = 0;
    tls_session -> nx_secure_tls_remote_session_active = 0;
    tls_session -> nx_secure_tls_received_remote_credentials = NX_FALSE;

    /* Reset alert tracking. */
    tls_session -> nx_secure_tls_received_alert_level = 0;
    tls_session -> nx_secure_tls_received_alert_value = 0;


    /* See if this is a TCP server started with listen/accept, or a TCP client started with connect. */
    if (tcp_socket -> nx_tcp_socket_client_type)
    {
        /* The TCP socket is a client, so our TLS session is a TLS Client. */
        tls_session -> nx_secure_tls_socket_type = NX_SECURE_TLS_SESSION_TYPE_CLIENT;
    }
    else
    {
        /* This session is now being treated as a server - indicate that fact to the TLS stack. */
        tls_session -> nx_secure_tls_socket_type = NX_SECURE_TLS_SESSION_TYPE_SERVER;
    }

#if (NX_SECURE_TLS_TLS_1_3_ENABLED)
    /* Initialize TLS 1.3 cryptographic primitives. */
    if(tls_session->nx_secure_tls_1_3)
    {
        status = _nx_secure_tls_1_3_crypto_init(tls_session);

        if(status != NX_SUCCESS)
        {

            /* Release the protection. */
            tx_mutex_put(&_nx_secure_tls_protection);
            return(status);
        }
    }
#endif

    /* Now process the handshake depending on the TLS session type. */
#ifndef NX_SECURE_TLS_CLIENT_DISABLED
    if (tls_session -> nx_secure_tls_socket_type == NX_SECURE_TLS_SESSION_TYPE_CLIENT)
    {

        /* Allocate a handshake packet so we can send the ClientHello. */
        status = _nx_secure_tls_allocate_handshake_packet(tls_session, tls_session -> nx_secure_tls_packet_pool, &send_packet, wait_option);

        if (status != NX_SUCCESS)
        {

            /* Release the protection. */
            tx_mutex_put(&_nx_secure_tls_protection);
            return(status);
        }

        /* Populate our packet with clienthello data. */
        status = _nx_secure_tls_send_clienthello(tls_session, send_packet);

        if (status == NX_SUCCESS)
        {

            /* Manally update nx_secure_tls_client_random. */
            memcpy(tls_session->nx_secure_tls_key_material.nx_secure_tls_client_random, client_random_bytes, client_random_bytes_len);

            /* Send the ClientHello to kick things off. */
            status = _nx_secure_tls_send_handshake_record(tls_session, send_packet, NX_SECURE_TLS_CLIENT_HELLO, wait_option);
        }

        /* If anything after the allocate fails, we need to release our packet. */
        if (status != NX_SUCCESS)
        {

            /* Release the protection. */
            tx_mutex_put(&_nx_secure_tls_protection);
            nx_secure_tls_packet_release(send_packet);
            return(status);
        }
    }
#endif

    /* Release the protection. */
    tx_mutex_put(&_nx_secure_tls_protection);

    /* Now handle our incoming handshake messages. Continue processing until the handshake is complete
       or an error/timeout occurs. */
    status = _nx_secure_tls_handshake_process(tls_session, wait_option);

    if ((status == NX_CONTINUE) && (wait_option == 0))
    {
        
        /* It is non blocking mode. */
        return(NX_CONTINUE);
    }

    if(status != NX_SUCCESS)
    {
        /* Save the return status before resetting the TLS session. */
        error_return = status;

        /* Reset the TLS state so this socket can be reused. */
        status = _nx_secure_tls_session_reset(tls_session);

        if(status != NX_SUCCESS)
        {
            return(status);
        }

        return(error_return);
    }

    return(status);
}

static void ntest_1_entry(ULONG thread_input)
{
UINT i;
UINT status;
NXD_ADDRESS server_address;

    server_address.nxd_ip_version = NX_IP_VERSION_V4;
    server_address.nxd_ip_address.v4 = IP_ADDRESS(127, 0, 0, 1);

    /* Create TCP socket. */
    status = nx_tcp_socket_create(&ip_0, &client_socket_0, "Client socket", NX_IP_NORMAL,
                                  NX_DONT_FRAGMENT, NX_IP_TIME_TO_LIVE, 8192, NX_NULL, NX_NULL);
    if (status)
    {
        ERROR_COUNTER();
    }

    status = nx_tcp_client_socket_bind(&client_socket_0, NX_ANY_PORT, NX_NO_WAIT);
    if (status)
    {
        ERROR_COUNTER();
    }


    for (i = 0; i < 1; i++)
    {

        /* Let server thread run first. */
        tx_thread_resume(&thread_0);

        client_tls_setup(&tls_client_session_0);

        status = _nx_secure_tls_session_packet_buffer_set(&tls_client_session_0, tls_packet_buffer,
                                                          TLS_PACKET_BUFFER_SZ);
        if (status)
        {
            ERROR_COUNTER();
        }

        status = nxd_tcp_client_socket_connect(&client_socket_0, &server_address, SERVER_PORT,
                                               NX_WAIT_FOREVER);
        if (status)
        {
            ERROR_COUNTER();
        }

        /* Start TLS session. */
        status = ntest_nx_secure_tls_session_start(&tls_client_session_0, &client_socket_0,
                                             NX_WAIT_FOREVER);

        /* For the sake of test simpicity, we didn't let server thread send following messages to client thread
            after it received FINISHED message from client, but let server thread just close TCP connection directly,
            so here ntest_nx_secure_tls_session_start() returned NX_NOT_CONNECTED. */
        EXPECT_EQ(NX_NOT_CONNECTED, status);

        nx_secure_tls_session_end(&tls_client_session_0, NX_NO_WAIT);
        nx_secure_tls_session_delete(&tls_client_session_0);

        nx_tcp_socket_disconnect(&client_socket_0, NX_NO_WAIT);
    }
}


#else
#ifdef CTEST
void test_application_define(void *first_unused_memory);
void test_application_define(void *first_unused_memory)
#else
VOID    nx_secure_tls_handshake_fragmentation_ecc_test_application_define(void *first_unused_memory)
#endif
{

    /* Print out test information banner.  */
    printf("NetX Secure Test:   TLS Handshake Fragmentation ECC Test...............N/A\n");
    test_control_return(3);
}
#endif
